package j2metris.game;

import j2metris.ControllablePiece;
import j2metris.Coordinate;

import j2metris.Direction;
import j2metris.util.LoopingList;

import javax.microedition.lcdui.Image;

final class PieceWithPosition extends ControllablePiece
{
    private final Coordinate[][] rotationStates;
    private final LoopingList rotationStateList;
    private final Image unitImage;
    private Coordinate position;
    private final String name;

    public PieceWithPosition(ControllablePiece original,
            Coordinate startingPosition)
    {
        Coordinate[][] origRotationStates = original.getRotationStates();
        rotationStates = new Coordinate[origRotationStates.length][];
        for(int i = 0; i < origRotationStates.length; ++i)
        {
            rotationStates[i] = new Coordinate[origRotationStates[i].length];
            System.arraycopy(origRotationStates[i], 0, rotationStates[i], 0,
                    origRotationStates[i].length);
        }

        name = original.toString();
        rotationStateList = new LoopingList(rotationStates);
        unitImage = Image.createImage(original.getUnitImage());
        position = startingPosition;
    }

    public Coordinate[] getRotationState()
    {
        return getRotationState(0);
    }

    public ControllablePiece clone()
    {
        return new PieceWithPosition(this, position);
    }

    public Coordinate[] getRotationState(int distanceFromCurrentState)
    {
        Coordinate[] rotationState = (Coordinate[]) rotationStateList.
                getObject(distanceFromCurrentState);
        Coordinate[] ret = new Coordinate[rotationState.length];
        System.arraycopy(rotationState, 0, ret, 0, rotationState.length);
        return ret;
    }

    public Coordinate[][] getRotationStates()
    {
        Coordinate[][] ret = new Coordinate[rotationStates.length][];
        for(int i = 0; i < rotationStates.length; ++i)
        {
            ret[i] = new Coordinate[rotationStates[i].length];
            System.arraycopy(rotationStates[i], 0, ret[i], 0,
                    rotationStates[i].length);
        }
        return ret;
    }

    public Image getUnitImage()
    {
        return Image.createImage(unitImage);
    }

    public void rotateClockwise()
    {
        rotationStateList.increment(1);
    }

    public void rotate(Direction.RotationDirection d, int value)
    {
        if(d == Direction.CLOCKWISE) rotationStateList.increment(value);
        else rotationStateList.increment(-value);
    }

    public void rotateCounterclockwise()
    {
        rotationStateList.increment(-1);
    }

    public Coordinate getPosition()
    {
        return position;
    }

    public Coordinate[] getAbsolutePositions()
    {
        Coordinate[] rotationState = getRotationState();
        Coordinate[] ret = new Coordinate[rotationState.length];
        for(int i = 0; i < ret.length; ++i)
        {
            ret[i] = rotationState[i].add(position);
        }
        return ret;
    }

    /**
     * Gets the coordinates that this <code>Piece</code> would be at if it were
     * moved in the specified direction the number of times specified.
     * @param d the direction in which the <code>Piece</code> would be moved
     * @param value the number of times the <code>Piece</code> would be moved in
     * the specified direction
     * @return an array of <code>Coordinate</code> that the piece would be at
     */
    public Coordinate[] getAbsolutePositions(Direction d, int value)
    {
        Coordinate[] ret;
        if(d.isARotationDirection())
        {
            Coordinate[] possibleState = getRotationState(value);
            ret = new Coordinate[possibleState.length];
            for(int i = 0; i < ret.length; ++i)
            {
                ret[i] = possibleState[i].add(position);
            }
        }
        else if(d == Direction.DOWN)
        {
            Coordinate[] rotationState = getRotationState();
            ret = new Coordinate[rotationState.length];
            for(int i = 0; i < ret.length; ++i)
            {
                ret[i] = rotationState[i].add(position).add(
                        new Coordinate(0, value));
            }
        }
        else if(d == Direction.LEFT)
        {
            Coordinate[] rotationState = getRotationState();
            ret = new Coordinate[rotationState.length];
            for(int i = 0; i < ret.length; ++i)
            {
                ret[i] = rotationState[i].add(position).add(
                        new Coordinate(value, 0));
            }
        }
        else if(d == Direction.RIGHT)
        {
            Coordinate[] rotationState = getRotationState();
            ret = new Coordinate[rotationState.length];
            for(int i = 0; i < ret.length; ++i)
            {
                ret[i] = rotationState[i].add(position).add(
                        new Coordinate(-value, 0));
            }
        }
        else //d == Direction.UP
        {
            Coordinate[] rotationState = getRotationState();
            ret = new Coordinate[rotationState.length];
            for(int i = 0; i < ret.length; ++i)
            {
                ret[i] = rotationState[i].add(position).add(
                        new Coordinate(0, -value));
            }
        }

        return ret;
    }

    public void setPosition(Coordinate positionParam)
    {
        position = positionParam;
//        if(J2metrisApp.DEBUG)
//            System.err.println("SETTING POSITION TO " + positionParam);
    }

    public void setPosition(int x, int y)
    {
        setPosition(new Coordinate(x, y));
    }

    public void setPosition(Direction.TranslationDirection d, int value)
    {
        Coordinate addition;
        if(d == Direction.DOWN) addition = new Coordinate(0, value);
        else if(d == Direction.LEFT) addition = new Coordinate(-value, 0);
        else if(d == Direction.RIGHT) addition = new Coordinate(value, 0);
        else addition = new Coordinate(0, -value);
        position = position.add(addition);
        System.err.println(position);
    }

    private boolean gravityShouldContinue = true;
    private boolean gravityShouldContinue()
    {
        return gravityShouldContinue;
    }

    public String toString()
    {
        return name;
    }
}
